#pragma once

#include "MBAxisAlignedBoundingBox.h"
#include "MBCameraView.h"
#include "MBCameraViewWithShiftVector.h"
#include "MBDataTypes.h"
#include "MBDistanceMap.h"
#include "MBEnums.h"
#include "MBHelperClasses.h"
#include "MBInvalidArgumentException.h"
#include "MBLabelingOptions.h"
#include "MBTriangle.h"

#include <map>
#include <vector>

/**
  *	The MBEnergyMinimizer is the essential part in the labeling process. It is
  * used to find an optimal mapping of textures (MBLabel) onto the triangles
  * (MBTriangle) of the model. The implemented methods to find this mapping
  * are "Best Fragment", "Markov Random Field", and "Markov Random Field with
  * Shift Vectors". Use the Solve() method to calculate the best mapping.
  */
class MBEnergyMinimizer
{
public:

	MBEnergyMinimizer(
		const MBTriangle *const *nodes,
		const MBuint &numNodes,
		const MBCameraView *const *labels,
		const MBuint &numLabels,
		const MBAxisAlignedBoundingBox &modelBoundingBox,
		const bool &useOnlyCamerasInModelBoundingBox );

	~MBEnergyMinimizer( void );

	const std::vector<const MBCameraView*> &Solve(
		const MBLabelingOptions &options,
		MBDistanceMap *distanceMap ) throw( MBInvalidArgumentException );

private:
	/** Vector with const pointers to all the MBTriangle objects in the labeling process  */
	std::vector<const MBTriangle *> mNodes;
	/** Vector with const pointers to all the MBCameraView objects in the labeling process */
	std::vector<const MBCameraView *> mLabels;
	/** Result of the labeling process. At index i there is a const pointer to the MBCameraView object that is used as a label for the MBTriangle object at mNodes[i] */
	std::vector<const MBCameraView *> mLabelingF;
	/** The same as mLabelingF, but these are newly generated MBCameraView objects for the labeling with shift vectors */
	std::vector<MBCameraView *> mLabelingFData;
	/** The camera views with shift vector used for the "Markov Random Field with Shift Vector" method */
	std::vector<MBCameraViewWithShiftVector *> *mCameraViewsWithShiftVector;

	/** Current pyramid level for the "Markov Random Field with Shift Vector" method  */
	MBuint mCurrentPyramidLevel;
	/** Number of samples along a single triangle edge calculated during a labeling operation */
	MBint mNumSamples;
	/** Weight for the V-Term, also called smooth cost term, where the integral of color differences along a seam is calculated */
	double mVTermWeight;
	/** Filtering mode used to sample the image positions */
	MBFilteringMode mFilteringMode;
	/** Boolean value indicating whether octree should be used or not */
	//bool mUseOctree;
	/** The Distance Map used for Occlusion Detection */
	MBDistanceMap *m_distanceMap;

	/** Labeling options */
	const MBLabelingOptions *mLabelingOptions;

	static double DataCostFunction( int nodeIndex, int labelIndex, void *minimizer );
	static double SmoothCostFunction( int firstNodeIndex, int secondNodeIndex, int firstLabelIndex, int secondLabelIndex, void *minimizer );

	static double DataCostFunctionWithShifting( int nodeIndex, int labelIndex, void *minimizer );
	static double SmoothCostFunctionWithShifting( int firstNodeIndex, int secondNodeIndex, int firstLabelIndex, int secondLabelIndex, void *minimizer );
};